﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace EventScavenger
{
    public delegate void MessageReceivedDelegate(EventCollectorInstance instance, Stream xmlStream);
    public class EventCollectorInstance
    {
        private static System.Threading.Mutex reportEventMutex = new System.Threading.Mutex();
        private EventLog eventLog;

        public event MessageReceivedDelegate MessageReceived;
        private void RaisedMessageReceived(Stream xmlStream)
        {
            if (MessageReceived != null)
            {
                MessageReceived(this, xmlStream);
            }
        }

        private string eventLogName = "";
        public string EventLogName
        {
            get { return eventLogName; }
            set
            {
                eventLogName = value;
            }
        }
        public string MachineName
        {
            get { return eventLog.MachineName; }
        }
        private DateTime lastMessageRaised = new DateTime(2000, 1, 1);
        public DateTime LastMessageRaised
        {
            get { return lastMessageRaised; }
        }

        public EventCollectorInstance(string eventLogName)
        {
            this.eventLogName = eventLogName;
            eventLog = new EventLog(eventLogName, System.Net.Dns.GetHostName());
        }

        private void eventLog_EntryWritten(object sender, EntryWrittenEventArgs e)
        {
            try
            {
                reportEventMutex.WaitOne();
                EventLogEntry entry = e.Entry;

                System.IO.MemoryStream outstream = new System.IO.MemoryStream();
                using (System.Xml.XmlTextWriter wrt = new System.Xml.XmlTextWriter(outstream, Encoding.UTF8))
                {
                    wrt.Formatting = System.Xml.Formatting.Indented;
                    wrt.Indentation = 1;
                    wrt.IndentChar = ' ';
                    wrt.WriteStartDocument();
                    wrt.WriteStartElement("rs");

                    wrt.WriteStartElement("r");
                    wrt.WriteAttributeString("cn", eventLog.MachineName);
                    wrt.WriteAttributeString("l", eventLogName);
                    wrt.WriteAttributeString("r", entry.Index.ToString());
                    int eventId = (int)(entry.InstanceId & 65535);
                    wrt.WriteAttributeString("e", eventId.ToString());
                    wrt.WriteAttributeString("t", entry.TimeGenerated.ToString("yyyy-MM-ddTHH:mm:ss"));
                    wrt.WriteAttributeString("s", entry.Source);
                    wrt.WriteAttributeString("et", entry.EntryType.ToString().ToUpper().Substring(0, 1));
                    wrt.WriteAttributeString("c", N(entry.Category));
                    wrt.WriteAttributeString("u", N(entry.UserName));
                    string message = entry.Message;
                    string strings = Encoding.UTF8.GetString(entry.Data, 0, entry.Data.Length);
                    if (message.Length == 0 && strings != null && strings.Length > 0)
                        if (!strings.Contains('�'))
                            message = strings;
                    message = message.Replace("\r\n", "\\r\\n");
                    wrt.WriteAttributeString("m", message);
                    wrt.WriteEndElement(); //r


                    wrt.WriteEndElement(); //rs
                    wrt.WriteEndDocument();
                    wrt.Flush();

                    outstream.Position = 0;
                    RaisedMessageReceived(outstream);
                    lastMessageRaised = DateTime.Now;
                }
            }
            catch { }
            finally
            {
                reportEventMutex.ReleaseMutex();
            }
        }

        #region Null handling
        private string N(object anyVal)
        {
            if (anyVal == null)
                return "";
            else
                return anyVal.ToString();
        }
        #endregion

        public void Start()
        {
            eventLog.EntryWritten += new EntryWrittenEventHandler(eventLog_EntryWritten);
            eventLog.EnableRaisingEvents = true;
        }

        public void Stop()
        {
            eventLog.EnableRaisingEvents = false;
            eventLog.EntryWritten -= new EntryWrittenEventHandler(eventLog_EntryWritten);
        }
    }
}
